#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "softUART.h"

//----------------------------------------------------------------------------------------  
// soft-uart library
// date: 5.April 2009
// by M. Ossmann

// RS232 sends D0 first !
// 'A'=0x41 = 0b01000001   is transmitted as 0100000101 ( on 5V side )
// start-bit==low, stop-bit==high ( on 5V side )

//---------------------GLOBAL VARIABLES---------------------------------------------------  

uint8_t RX1fifo[RX1fifoSIZE] ;       // we reserve a power of 2 as space
volatile uint8_t RX1fifoPutIdx ;     // PutIdx always points to the (free) place where the next item is put   
volatile uint8_t RX1fifoGetIdx ;     // GetIdx  always points to the (filled) place from which to fech item

// if PutIdx==GetIdx the FIFO is considered empty
// if PUTidx+1==GetIdx the FIFO is considered full
// notice: When the fifo is considered full, there is still one place left, so we do nut fully
// use the available space in the FIFO array. But this makes the index-arithmetic
// and empty/full detection simpler.

uint8_t RX1idle ;     // ==1 if the uart searches for the start-bit,
	                  // ==0 if the uart actually receives bits of a byte
uint8_t RX1timer ;    // counts down by UARTclk until==0, the next action will happen
                      // When startbit is detected, this counter is used to dely until the middle
					  // of the first data-bit is reached. Thereafter this counter is used to
					  // delay for one bit-time of the uart = 4 UARTclks
uint8_t RX1bitCount ; // How many bits are left to receive, counts down
uint8_t RX1shiftReg ; // The received byte is composed in this byte
uint8_t RX1bitMask ;  // mask to fill in new bit a right position

//-------------------------------- FUNCTION DEFINITIONS -----------------------------------  

void Timer0init() {
  TCCR0  = 0b00001011 ; // CTC mode, predivder=64
  TIMSK |= 0b00000010 ;
//	TCCR0  = 0b00001001 ; // CTC mode, predivder=1
//	TIMSK |= 0b00000010 ;
//  OCR0=139-1           ; // 16000000MHz/139=115107.91... Hz is approx 4*28800=115200
                         // so timer 1 generates UARTclk and that is 4 times the wante bit-rate


	OCR0=(13 * (4800 / SOFTUART_BAUD_RATE) -1); // Sp: modified to select other baudrates
  }
  
//----------------------------------RECEIVE RxD-------------------------------------------  

void RX1init(){
  RX1_DDR  &= ~ _BV(RX1_BIT) ; // make input
  RX1_PORT |=   _BV(RX1_BIT) ; // with pullup
  RX1fifoPutIdx=0 ;
  RX1fifoGetIdx=0 ; // PutIdx==GetIdx signals FIFO empty

  RX1idle=1           ; // true, we seearch for start-bit
  }


uint8_t RX1fifoEmpty(){
  return ( RX1fifoPutIdx == RX1fifoGetIdx ) ;
  }

uint8_t getRX1char(){
  while ( RX1fifoEmpty() ) { }                        // while FIFO empty WAIT
  uint8_t c=RX1fifo[RX1fifoGetIdx] ;              // fetch from FIFO
  RX1fifoGetIdx=(RX1fifoGetIdx+1) & RX1fifoMASK ; // and update index
  return c ;
  }

uint8_t getRX1char_nw(){				// Sp: added to return immediately if nothing received
  uint8_t c;
  if (RX1fifoEmpty())                  // if FIFO empty RETURN
    return 0;
  else {
  	c=RX1fifo[RX1fifoGetIdx] ;              // fetch from FIFO
  	RX1fifoGetIdx=(RX1fifoGetIdx+1) & RX1fifoMASK ; // and update index
  return c ;
  }
}

// Interrupt routine
ISR(TIMER0_COMP_vect) {
  //PORTD |=    _BV(2) ; // for tests only
  if ( RX1idle ){                             // if idle search for start bit
    if ( (RX1_PIN & _BV(RX1_BIT ))==0) {      // 0 on imput indicates start bit
	  RX1timer=RX1_DELAY1 ;                   // delay to middle of first data-bit
	  RX1bitCount=9 ;                         // get 8 data-bits and 1 stop bit
	  RX1idle=0 ;                             // we are no longer idle
	  RX1bitMask=1 ;                          // start bit-fill-in at LSBit of byte  
	  RX1shiftReg=0 ;                         // clear data byte
	  } // end if start bit
    } // end if RX1idle
   else { 
    RX1timer-- ;                               // one tick delay 
    if (RX1timer==0){                          // delay time is over if timer reaches 0
      if ( (RX1_PIN & _BV(RX1_BIT )) != 0 ) {  // if we have a 1 on the input pin
	    RX1shiftReg |= RX1bitMask ;            // we set the 1 at the right position
		}
	  RX1bitMask = RX1bitMask << 1 ;           // next bit position
	  RX1timer=RX1_DELAY2 ;                    // delay to next middle  
      RX1bitCount-- ;                          // count down bits
	  if (RX1bitCount==0) {                    // reaching 0 we  did all bits
	    RX1idle=1 ;                            // go back to start-search-mode
		RX1fifo[RX1fifoPutIdx]=RX1shiftReg  ;  // put received byte into FIFO
        RX1fifoPutIdx=(RX1fifoPutIdx+1) & RX1fifoMASK ; // and update indexes
		}
	  }
    }
  //PORTD &= ~ _BV(2) ;                         // for tests only
//--------------------------------------------------------
  TX1timer-- ;                                  // count-down until bit-time is over
  if (TX1timer==0){                             // bit-time is over
    TX1timer=TX1_DELAY  ;
	if (TX1shiftReg){                           // shiftreg !=0 means the stop bit has not been sent
	  if ( TX1shiftReg & 1 ) {                  // test LSbit
	    TX1_PORT |= _BV(TX1_BIT) ;              // if 1 send 1  
		} 
	   else { 
	    TX1_PORT &= ~ _BV(TX1_BIT) ;            // if 0 send 0
		}
	  TX1shiftReg=TX1shiftReg >> 1 ;            // shift to new position
	  }
	 else{                                      // if last char has been send
	  if ( TX1fifoPutIdx != TX1fifoGetIdx ) {   // test for further characters in FIFO
	    TX1shiftReg=(TX1fifo[TX1fifoGetIdx] << 1) | 0x200 ;  // fetch char and generate bit-pattern
        TX1fifoGetIdx=(TX1fifoGetIdx+1) & TX1fifoMASK ;      // update FIFO indexes
		}
	  }
    }
  }
  
  void TX1init(){ 
  TX1fifoPutIdx=0 ;
  TX1fifoGetIdx=0 ; // PutIdx==GetIdx signals FIFO empty
  TX1timer=4 ;
  TX1_DDR  |= _BV(TX1_BIT) ; // pin = output
  TX1_PORT |= _BV(TX1_BIT) ; // 1=idle
  }

void TX1char(uint8_t c){
  uint8_t nxt ;
  nxt=(TX1fifoPutIdx+1) & TX1fifoMASK  ; // compute next value of TX1fifoPutIdx
  while(nxt==TX1fifoGetIdx) {            // compare putidx+1 with getidx, equal means full
     }                                   // wait while FIFO full
  TX1fifo[TX1fifoPutIdx]=c ;             // enter character into fifo
  TX1fifoPutIdx=nxt ;
  }

void TX1string(const char *s )			 // Sp: added from UART lib
{
    while (*s)
      TX1char(*s++);
}

void TX1string_p(const char *progmem_s)  // Sp: added from UART lib
{
    register char c;

    while ( (c = pgm_read_byte(progmem_s++)) )
      TX1char(c);
}
